package cc.bukkitPlugin.banitem.check.nbtvalue;

import java.util.List;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;

import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;

import cc.bukkitPlugin.util.plugin.ABukkitPlugin;

public class ExpressNBTValue extends ANBTValue{

    private static ScriptEngine mJSEngine;

    static{
        ScriptEngineManager tEngineMan=new ScriptEngineManager(ClassLoader.getSystemClassLoader());
        ExpressNBTValue.mJSEngine=tEngineMan.getEngineByName("JavaScript");
        if(ExpressNBTValue.mJSEngine==null){
            ABukkitPlugin.severe("无法获取JavaScript解析引擎");
            ABukkitPlugin.severe("所有可用的解析引擎: ");
            List<ScriptEngineFactory> tEngines=new ScriptEngineManager(ClassLoader.getSystemClassLoader()).getEngineFactories();
            for(ScriptEngineFactory sEngines : tEngines){
                ABukkitPlugin.severe("名字列表: "+sEngines.getNames()+"  解析器: "+sEngines.getScriptEngine().getClass().getSimpleName());
            }
        }
    }

    private boolean mHasPram;

    public ExpressNBTValue(String pValue){
        super(pValue);
        this.mHasPram=ExpressNBTValue.mJSEngine==null||this.mValue.indexOf("%value%")!=-1;
        if(this.mHasPram){
            this.mHasPram=ExpressNBTValue.isValidExpress(this.mValue,null,false);
            if(!this.mHasPram){
                ABukkitPlugin.severe("将["+this.mValue+"]作为普通字符串进行比较");
            }
        }
    }

    @Override
    public boolean isInRange(String pStrValue){
        if(pStrValue==null)
            return false;
        if(!this.mHasPram)
            return this.mValue.equals(pStrValue);
        Object tResult=ExpressNBTValue.getJsCalcResult(ExpressNBTValue.getConstructExpress(this.mValue,pStrValue));
        if(tResult!=null&&tResult instanceof Boolean){
            return ((Boolean)tResult).booleanValue();
        }else{
            if(tResult==null){
                ABukkitPlugin.severe("无法解析JS表达式["+this.mValue+"], 变量: "+pStrValue);
            }else ABukkitPlugin.severe("JS表达式["+this.mValue+"],变量: "+pStrValue+",的解析结果不是Boolean类型");
        }
        return false;
    }

    /**
     * 测试脚本是否正确
     * <p>函数内会发送错误消息</p>
     * @param pExpress 测试的脚本
     * @param pSender 发送错误消息给谁,可以为null
     * @return 是否正确
     */
    public static boolean isValidExpress(String pExpress,CommandSender pSender,boolean pNotify){
        if(pSender==null)
            pSender=Bukkit.getConsoleSender();
        ExpressNBTValue.sendMsg(pSender,"测试JS脚本["+pExpress+"]",pNotify);
        boolean numbValid=false,stringValid=false;
        String testNumb="12345",testString="abcde";
        // 测试数字计算结果是否正常
        ExpressNBTValue.sendMsg(pSender,"测试数字变量["+testNumb+"]的解析",pNotify);
        String constructExpress=ExpressNBTValue.getConstructExpress(pExpress,testNumb);
        Object tResult=ExpressNBTValue.getJsCalcResult(constructExpress);
        if(tResult==null)
            ExpressNBTValue.sendMsg(pSender,"解析结果: &c解析失败("+constructExpress+")",pNotify);
        else ExpressNBTValue.sendMsg(pSender,"解析结果: "+tResult+"("+constructExpress+")",pNotify);
        if(tResult!=null&&tResult instanceof Boolean)
            numbValid=true;
        // 测试字符串计算结果是否正常
        ExpressNBTValue.sendMsg(pSender,"测试字符串变量["+testString+"]的解析",pNotify);
        constructExpress=ExpressNBTValue.getConstructExpress(pExpress,testString);
        tResult=ExpressNBTValue.getJsCalcResult(constructExpress);
        if(tResult==null)
            ExpressNBTValue.sendMsg(pSender,"解析结果: &c解析失败("+constructExpress+")",pNotify);
        else ExpressNBTValue.sendMsg(pSender,"解析结果: "+tResult+"("+constructExpress+")",pNotify);
        if(tResult!=null&&tResult instanceof Boolean)
            stringValid=true;

        if(!(numbValid||stringValid)){
            ABukkitPlugin.send(pSender,"错误的JS表达式["+pExpress+"],该表达式无法进行JS语法解析或解析结果不是Boolean类型");
        }
        return numbValid||stringValid;
    }

    private static void sendMsg(CommandSender pSender,String pMsg,boolean pNotify){
        if(pSender==null)
            pSender=Bukkit.getConsoleSender();
        if(pNotify){
            ABukkitPlugin.send(pSender,pMsg);
        }else{
            ABukkitPlugin.debug(pMsg);
        }
    }

    private static String getConstructExpress(String pExpress,String pParam){
        if(pParam==null)
            pParam="";
        pParam=pParam.replace("\\","\\\\").replace("\"","\\\"").replace("'","\\'");
        return pExpress.replace("%value%",pParam);
    }

    /**
     * 使用指定的值替换表达式的%value%变量并返回计算结果
     * <p>解析错误或参数不正确将返回null</p>
     * @param pExpress JS表达式
     * @param pParam 值
     * @param pNotify 是否显示消息给发送者,如果false将以debug方式显示
     * @return 结果
     */
    private static Object getJsCalcResult(String pConstructExpress){
        if(pConstructExpress==null)
            return null;
        try{
            return ExpressNBTValue.mJSEngine.eval(pConstructExpress);
        }catch(Throwable exp){
            return null;
        }
    }

}
